local test = UnitTest:New("06DongleDB")
local Dongle = DongleStub("Dongle-1.0")

function test:dongle_initialize_db()
	assert_fails(function() Dongle.InitializeDB({}) end, "You must call 'InitializeDB' from a registered Dongle.")

	local tau = Dongle:New("Tau")
	assert_fails(function() tau:InitializeDB(1) end, argerror(2))
	assert_fails(function() tau:InitializeDB("test", 1) end, argerror(3))
	assert_fails(function() tau:InitializeDB("test", nil, 1) end, argerror(4))
	
	local db = tau:InitializeDB("TauDB")
	assert(type(db) == "table")
	assert(rawget(db, "faction") == nil)
	assert(rawget(db, "realm") == nil)
	assert(rawget(db, "class") == nil)
	assert(rawget(db, "global") == nil)
	assert(rawget(db, "profile") == nil)

	assert(db:GetCurrentProfile() == ("%s - %s"):format(UnitName("player"), GetRealmName()))

	local sv = {}
	local db = tau:InitializeDB(sv)
	assert(type(db) == "table")
	assert(db.sv_name == sv)	
end

function test:dongle_register_db_defaults()
	assert_fails(function() Dongle.RegisterDefaults({}) end, "You must call 'RegisterDefaults' from a Dongle database object.")

	local upsilon = Dongle:New("Upsilon")
	local db = upsilon:InitializeDB("UpsilonDB")

	assert_fails(function() db:RegisterDefaults(1) end, argerror(2))

	local sv = UpsilonDB
	local defaults = {
		char = {
			Alpha = true,
			Eta = {
				Iota = true
			},
		},
		faction = {
			Beta = true,
		},
		realm = {
			Gamma = true,
		},
		class = {
			Delta = true,
		},
		global = {
			Epsilon = true,
		},
		profile = {
			Zeta = true,
		},
	}

	db:RegisterDefaults(defaults)
	assert(db.char.Alpha == true)
	assert(db.faction.Beta == true)
	assert(db.realm.Gamma == true)
	assert(db.class.Delta == true)
	assert(db.global.Epsilon == true)
	assert(db.profile.Zeta == true)
	assert(db.char.Eta.Iota == true)

	local upsilon = Dongle:New("Upsilon2")
	local db = upsilon:InitializeDB("UpsilonDB2", nil, "Some Profile")
	assert(db.keys.profile == "Some Profile")
end

function test:dongle_clear_db_defaults()
	local phi = Dongle:New("Phi")
	local chi = Dongle:New("Chi")
	
	local defaults = {
		profile = {
			Alpha = true,
			Beta = {
				Gamma = true,
			},
		}
	}
	
	local phidb = phi:InitializeDB("PhiDB", defaults)
	local chidb = chi:InitializeDB("ChiDB", defaults)

	phidb.profile.Alpha = false
	chidb.profile.Beta.Gamma = false
	
	Dongle:ClearDBDefaults()
	assert(phidb.profile.Alpha == false)
	assert(not phidb.profile.Beta)
	assert(chidb.profile.Beta.Gamma == false)
	assert(not chidb.profile.Alpha)
end

function test:dongle_set_profile()
	assert_fails(function() Dongle.SetProfile("test") end, "You must call 'SetProfile' from a Dongle database object.")
	local psi = Dongle:New("Psi")
	local db = psi:InitializeDB("PsiDB", {profile = {Alpha = true}})

	assert_fails(function() db:SetProfile(1) end, argerror(2))
	
	local regKey = string.format("%s - %s", UnitName("player"), GetRealmName())
	assert(db.keys.profile == regKey)
	local old = db.profile
	
	db:SetProfile("Test Profile")
	assert(db.keys.profile == "Test Profile")
	assert(old ~= db.profile)
	assert(db.profile.Alpha == true)
end

function test:dongle_delete_profile()
	assert_fails(function() Dongle.DeleteProfile("test") end, "You must call 'DeleteProfile' from a Dongle database object.")
	local omega = Dongle:New("Omega")
	local db = omega:InitializeDB("OmegaDB")

	assert_fails(function() db:DeleteProfile(1) end, argerror(2))
	
	omega:RegisterMessage("DONGLE_PROFILE_DELETED")
	function omega:DONGLE_PROFILE_DELETED()
		omega.alpha = true
	end	
	
	local regKey = string.format("%s - %s", UnitName("player"), GetRealmName())
	assert(db.keys.profile == regKey)
	db:SetProfile("Test Profile")
	assert_fails(function() db:DeleteProfile("Test Profile") end, "You cannot delete your active profile. Change profiles, then attempt to delete.")
	
	assert(not omega.alpha)
	db:DeleteProfile(regKey)
	assert(omega.alpha)
	assert(not OmegaDB.profiles[regKey])
end

function test:dongle_copy_profile()
	assert_fails(function() Dongle.CopyProfile("test") end, "You must call 'CopyProfile' from a Dongle database object.")
	local alice = Dongle:New("Alice")
	local db = alice:InitializeDB("AliceDB")

	assert_fails(function() db:CopyProfile(1) end, argerror(2))
	
	alice:RegisterMessage("DONGLE_PROFILE_COPIED")
	function alice:DONGLE_PROFILE_COPIED()
		alice.alpha = true
	end
	
	db.profile.Alpha = true
	db.profile.Beta = {Gamma = true}
	
	local regKey = string.format("%s - %s", UnitName("player"), GetRealmName())
	assert(db.keys.profile == regKey)
	db:SetProfile("Test Profile")
	assert_fails(function() db:CopyProfile("Test Profile") end, "Source/Destination profile cannot be the same profile")
	db:CopyProfile(regKey)
	assert(db.profile.Alpha == true)
	assert(db.profile.Beta.Gamma == true)
	assert(alice.alpha == true)
end

function test:dongle_reset_profile()
	assert_fails(function() Dongle.ResetProfile() end, "You must call 'ResetProfile' from a Dongle database object.")
	local bob = Dongle:New("Bob")
	
	bob:RegisterMessage("DONGLE_PROFILE_RESET")
	function bob:DONGLE_PROFILE_RESET()
		bob.alpha = true
	end
	
	local db = bob:InitializeDB("BobDB")
	
	db.profile.Alpha = true
	db.profile.Beta = {Gamma = true}
	
	local regKey = string.format("%s - %s", UnitName("player"), GetRealmName())
	assert(db.keys.profile == regKey)

	db:ResetProfile()
	
	assert(db.profile.Alpha == nil)
	assert(db.profile.Beta == nil)
	assert(bob.alpha == true)
end

function test:dongle_reset_db()
	assert_fails(function() Dongle.ResetDB() end, "You must call 'ResetDB' from a Dongle database object.")
	local carol = Dongle:New("carol")
	
	carol:RegisterMessage("DONGLE_DATABASE_RESET")
	carol:RegisterMessage("DONGLE_PROFILE_CHANGED")
	carol:RegisterMessage("DONGLE_PROFILE_CREATED")

	function carol:DONGLE_DATABASE_RESET()
		carol.alpha = true
	end
	function carol:DONGLE_PROFILE_CHANGED()
		carol.beta = true
	end
	function carol:DONGLE_PROFILE_CREATED()
		carol.gamma = true
	end

	local db = carol:InitializeDB("carolDB")		
	db.profile.Alpha = true
	db.profile.Beta = {Gamma = true}
	
	local regKey = string.format("%s - %s", UnitName("player"), GetRealmName())
	assert(db.keys.profile == regKey)

	db = db:ResetDB("SomeProfile")
	
	assert(db.profile.Alpha == nil)
	assert(db.profile.Beta == nil)
	assert(carol.alpha == true)
	assert(carol.beta == true)
	assert(carol.gamma == true)
	assert(db.keys.profile == "SomeProfile")
end

function test:dongle_db_retain_values()
	local joan = Dongle:New("joan")
	local defaults = {
		profile = {
			alpha = {
				beta = false
			},
			gamma = false,
		}
	}
	
	local db = joan:InitializeDB("joanDB", defaults)
	db.profile.alpha.beta = true
	db.profile.epsilon = true
	
	-- Simulate logout/login
	Dongle:ClearDBDefaults()
	
	local rivers = Dongle:New("rivers")
	db = rivers:InitializeDB("joanDB", defaults)
	
	assert(db.profile.alpha.beta == true)
	assert(db.profile.epsilon == true)
	assert(db.profile.gamma == false)    
end

function test:dongle_db_sv_globals()
	local alpha = Dongle:New("alpha")
	local db = alpha:InitializeDB("alphaDB")
	
	betaDB = {}
	local bdb = betaDB
	local db2 = alpha:InitializeDB("betaDB")
	
	assert(db.sv == alphaDB)
	assert(db2.sv == betaDB)
	assert(betaDB == bdb)
end

function test:dongle_db_list_profiles()
	local dianne = Dongle:New("dianne")
	local db = dianne:InitializeDB("dianneDB",nil,"Initial Profile")
	assert(db.profile)
	db:SetProfile("SomeProfile")
	assert(db.profile)
	db:SetProfile("SomeOtherProfile")
	assert(db.profile)
	local profiles = {["Initial Profile"] = 1, ["SomeProfile"] = 1, ["SomeOtherProfile"] = 1}
	local p,n = db:GetProfiles()

	for k,v in pairs(p) do
		assert(profiles[v] == 1)
		profiles[v] = nil
	end
	assert(next(profiles) == nil)
	assert(#p == n)
end

function test:dongle_dynamic_db()
	local dyn = Dongle:New("dynamictable")
	dyn.db = dyn:InitializeDB("DYNDB")

	for k,v in pairs(dyn.db.keys) do
		assert(not rawget(dyn.db, k))
	end
end

function test:dongle_db_namespaces()
	local master = Dongle:New("masterDongle")
	master.db = master:InitializeDB("MasterDB", nil, "Test Profile")
	
	local child = Dongle:New("childDongle")
	child.db = master.db:RegisterNamespace("myNamespace")

	local key = "Test Profile"
	assert(master.db.keys.profile == key)
	assert(child.db.keys.profile == key)
end


function test:dongle_namespace_setprofile()
	local master = Dongle:New("nstestprofilemaster")
	master.db = master:InitializeDB("MasterDB")
	
	local child = master:NewModule("nstestprofilechild")
	child.db = master.db:RegisterNamespace("TestProfileNS")

	assert(master.db.keys.profile == child.db.keys.profile)
	master.db:SetProfile("TestProfileNS2")
	assert(master.db.keys.profile == child.db.keys.profile)
end

function test:dongle_magic_tables()
	local addon = Dongle:New("magic_tables")
	local defaults = {
		profile = {
			subtable = {
				["*"] = {
					alpha = 1,
					beta = 2,
				},
			},
		},
	}

	local db = addon:InitializeDB("magic_tablesDB", defaults)
	assert(type(db.profile) == "table")
	assert(type(db.profile.subtable) == "table")
	assert(db.profile.subtable[1].alpha == 1)
	assert(db.profile.subtable[1].beta == 2)
	
	db.profile.subtable[1].beta = 3
	Dongle:ClearDBDefaults()

	assert(db.profile.subtable[1].alpha == nil)
	assert(db.profile.subtable[1].beta == 3)
end

test:Run()